package org.zizi.manager;

import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.zizi.dao.InlandRevenueOrgDao;
import org.zizi.dao.UserDao;
import org.zizi.dao.UserInfoDao;
import org.zizi.db.EasySql;
import org.zizi.db.build.DataSourceBuilder;
import org.zizi.db.build.EasySqlBuilder;
import org.zizi.db.build.EasySqlConfig;
import org.zizi.manager.impl.DaoManager;
import org.zizi.modal.InlandRevenueOrg;
import org.zizi.modal.User;
import org.zizi.modal.UserInfo;
import org.zizi.util.Options;

public class BasicDataSyncManager extends TimerTask implements Manager
{
	private static Logger log = Logger.getLogger(BasicDataSyncManager.class);
	
	//是否启用
	private static final String DATA_SYNC_ENABLED = "BasicDataSyncEnabled";
	//数据连接配置
	private static final String DATABASE_TYPE = "BasicDataSyncDatabaseType";
	private static final String DATABASE_SERVER = "BasicDataSyncDatabaseServer";
	private static final String DATABASE_PORT = "BasicDataSyncDatabasePort";
	private static final String DATABASE_NAME = "BasicDataSyncDatabaseName";
	private static final String DATABASE_USER = "BasicDataSyncDatabaseUser";
	private static final String DATABASE_PASSWORD = "BasicDataSyncDatabasePassword";
	private static final String DATABASE_MAX_CONNECTIONS = "BasicDataSyncDatabaseMaxConnections";
	//数据库编码
	private static final String DATABASE_CHARSET = "BasicDataSyncDatabaseCharset";
	private static final String JAVA_RUNTIME_CHARSET = "JavaRuntimeCharset";
	//数据查询SQL
	private static final String DATA_SYNC_LIST_ORG_SQL = "BasicDataSyncListOrgSql";
	private static final String DATA_SYNC_LIST_OPERATOR_SQL = "BasicDataSyncListOperatorSql";
	private static final String DATA_SYNC_LIST_VAT_USER_SQL = "BasicDataSyncListVatUserSql";
	//数据同步时间设置
	private static final String DATA_SYNC_TIME = "BasicDataSyncTime";
	private static final String DATA_SYNC_DELAY = "BasicDataSyncDelay";
	
	private static final int TRANSACTION_READ_COMMITTED = 2;
	
	//
	private boolean enabled;
	
	//sql
	private EasySqlConfig config;
	private EasySql esql;
	private DataSource source;
	
	private String listOrgSql;
	private String listOperatorSql;
	private String listVatUserSql;
	
	//timer
	private String time;
	private Integer delay;			//每隔多久同步一次。单位：天
	private Timer timer;
	
	//同步时，暂存税务机关代码
	private Set<String> cache = new HashSet<String>();
	
	public void initialize(Options options) throws Exception
	{
		enabled = options.get(DATA_SYNC_ENABLED, Boolean.class, true);
		if (enabled)
		{
			initDatabaseConnection(options);
			
			listOrgSql = options.get(DATA_SYNC_LIST_ORG_SQL, String.class);
			listOperatorSql = options.get(DATA_SYNC_LIST_OPERATOR_SQL, String.class);
			listVatUserSql = options.get(DATA_SYNC_LIST_VAT_USER_SQL, String.class);
			
			time = options.get(DATA_SYNC_TIME, String.class, "1:0:0");
			delay = options.get(DATA_SYNC_DELAY, Integer.class, 1);
			
			log.info("启动基础数据同步服务：运行时间为" + time + "，间隔时间" + delay + "天。");
			
			schedule();
		}
	}
	
	public void run()
	{
		DaoManager dm = Managers.get(DaoManager.class);
		
		try
		{
			cache.clear();
			log.info("开始基础数据同步...");
			
			esql.begin(TRANSACTION_READ_COMMITTED, source);
			
			dm.begin();
			syncInlandRevenueOrgs();
			dm.commit();
			
			dm.begin();
			syncUser();
			dm.commit();
			
			dm.begin();
			syncUserInfo();
			dm.commit();
			
			esql.commit();
			
			log.info("基础数据同步完成.");
			cache.clear();
		}
		catch (Exception e)
		{
			log.error("基础数据同步错误：", e);
		}
		finally
		{
			dm.end();
			esql.end();
		}
	}
	
	
	private void initDatabaseConnection(Options options) throws Exception
	{
		String type = options.get(DATABASE_TYPE, String.class);
		String server = options.get(DATABASE_SERVER, String.class);
		Integer port = options.get(DATABASE_PORT, Integer.class);
		String name = options.get(DATABASE_NAME, String.class);
		String user = options.get(DATABASE_USER, String.class);
		String password = options.get(DATABASE_PASSWORD, String.class);
		Integer connections = options.get(DATABASE_MAX_CONNECTIONS, Integer.class, null);
		
		String javaCharset = options.get(JAVA_RUNTIME_CHARSET, String.class, null);
		String databaseCharset = options.get(DATABASE_CHARSET, String.class, null);
		
		config = new EasySqlConfig();
		config.setDatabase(type);
		config.setServer(server);
		config.setPort(port);
		config.setName(name);
		config.setUser(user);
		config.setPassword(password);
		config.setMax(connections);
		
		esql = EasySqlBuilder.build(type);
		source = DataSourceBuilder.build(config);
		
		esql.charset().setJavaCharset(javaCharset);
		esql.charset().setDatabaseCharset(databaseCharset);
	}
	

	private void schedule() throws Exception
	{
		timer = new Timer();

		long d = 86400000L * delay; //24 * 60 * 60 * 1000; 	//一天
		Date t = getFirstTime();
		
		timer.schedule(this, t, d);
	}
	
	
	private Date getFirstTime()
	{
		String[] xxx = time.split(":");
		int h = Integer.parseInt(xxx[0]);
		int m = Integer.parseInt(xxx[1]);
		int s = Integer.parseInt(xxx[2]);
		
		Calendar now = Calendar.getInstance();		//now
		
		Calendar start = Calendar.getInstance();	//
		start.set(Calendar.HOUR_OF_DAY, h);
		start.set(Calendar.MINUTE, m);
		start.set(Calendar.SECOND, s);
		
		if (now.after(start)) start.add(Calendar.DATE, 1);
		
		return start.getTime();
	}
	
	
	public void destory()
	{
		if (timer != null) timer.cancel();
	}
	
	//同步机关
	private void syncInlandRevenueOrgs() throws Exception
	{
		log.info("开始同步税务机关数据...");
		
		List<InlandRevenueOrg> list = esql.list(InlandRevenueOrg.class, listOrgSql);
		if (list == null) return;
		
		int counter = 0;
		InlandRevenueOrgDao dao = Managers.get(DaoManager.class).getDao(InlandRevenueOrgDao.class);
		for (InlandRevenueOrg org : list)
		{
			org.setName(org.getName());
			
			cache.add(org.getCode());
			dao.addOrUpdateInlandRevenueOrg(org);
			
			counter++;
			if (counter == 1 || (counter % 1000) == 0) log.info("正在同步第" + counter + "/" + list.size() + "条数据...");
		}
		
		log.info("同步税务机关数据完成，共" + list.size() + "条.");
	}
	
	private void syncUser() throws Exception
	{
		log.info("开始同步主管税务人员数据...");
		
		List<User> list = esql.list(User.class, listOperatorSql);
		if (list == null) return;
		
		int counter = 0;
		UserDao dao = Managers.get(DaoManager.class).getDao(UserDao.class);
		for (User u : list)
		{
			u.setName(u.getName());
			
			//查询本地user
			User local = dao.getUserByNsrdzdah(u.getNsrdzdah());
			if (local != null)
			{
				u.setId(local.getId());
				u.setEmpowerUser(local.isEmpowerUser());
				u.setMaintainCredit(local.isMaintainCredit());
				u.setMaintainType(local.isMaintainType());
			}
			
			counter++;
			if (counter == 1 || (counter % 1000) == 0) log.info("正在同步第" + counter + "/" + list.size() + "条数据...");
			
			if (!cache.contains(u.getOrgCode()))
			{
				log.warn("主管税务人员" + u.getName() + "(" + u.getLogin() + ")的机关代码 " + u.getOrgCode() + " 不存在于税务机关表中，舍弃此条记录。");
				continue;
			}
			
			dao.addOrUpdateUser(u);
		}
		
		log.info("同步主管税务人员数据完成，共" + list.size() + "条.");
	}
	
	private void syncUserInfo() throws Exception
	{
		log.info("开始同步纳税人数据...");
		
		UserInfoDao dao = Managers.get(DaoManager.class).getDao(UserInfoDao.class);
		
		int total = esql.query(Integer.class, parseSql(listVatUserSql));
		
		int offset = 0;
		int limit = 10000;
		int count = 0;
		
		while (true)
		{
			offset = count * limit;
			List<UserInfo> list = esql.page(UserInfo.class, offset, limit, listVatUserSql);
			if (list == null || list.isEmpty()) break;
			
			log.info("正在同步第" + offset + "-" + (offset + limit) + "条数据（共" + total + "条）...");
			
			count++;
			
			for (UserInfo u : list)
			{
				u.setName(u.getName());
				u.setAddress(u.getAddress());
				
				if (!cache.contains(u.getOrgCode()))
				{
					log.warn("纳税人" + u.getName() + "(" + u.getIdentify() + ")的机关代码 " + u.getOrgCode() + " 不存在于税务机关表中，舍弃此条记录。");
					continue;
				}
				
				dao.addOrUpdateUserInfo(u);
			}
		}
		
		log.info("同步纳税人数据完成，共" + total + "条.");
	}
	
//	//汉字转码
//	private String encode(String source) throws UnsupportedEncodingException
//	{
//		if (source == null || source.isEmpty()) return source;
//		return new String(source.getBytes("ISO8859-1"), "GBK");
//	}
	
	//将SQL转换为查询count
	private String parseSql(String sql)
	{
		int e = sql.indexOf("from");
		return "select count(*) " + sql.substring(e);
	}
}
